using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace UniC10_Plugin_Sample
{
    public partial class frmMain : Form
    {
        private int lastCodingSteps = 0;
        private int currentCodingSteps = 0;
        private int numCommissions = 0;

        #region DLL function declarations

        [DllImport("UniC10_Plugin.dll")]
        public static extern void GetRegisteredReaderNames(ref IntPtr readerNames);

        [DllImport("UniC10_Plugin.dll")]
        public static extern void FreeWideChar(IntPtr wideChar);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int ConnectReader(IntPtr readerName, byte comPort, uint baudrate, byte stopbits, 
            byte databits, byte parity);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int PrepareCoding(IntPtr commXML, IntPtr codingCallback, IntPtr parent,
            ref int estimatedCreationSteps, ref byte hasCardID, ref IntPtr maxCardID, ref IntPtr varData);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int AnalyzeCodingMask(IntPtr commXML, ref IntPtr transType, ref byte hasCardID,
            ref IntPtr maxCardID, ref IntPtr varData);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int GetLaserParameters(IntPtr commXML, ref IntPtr frontLayout, ref IntPtr frontParameters, ref IntPtr backLayout,
            ref IntPtr backParameters);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int Code(IntPtr cardID, IntPtr varData);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int SleepAndCode(IntPtr cardID, IntPtr varData, Int32 searchSleep);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int CodeWithCallback(IntPtr cardID, IntPtr varData, Int32 searchSleep, TCodingCallback codingCallback);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int SyncCode(IntPtr cardID, IntPtr varData, ref IntPtr cardUID, ref IntPtr cardIDAfterCode, ref IntPtr errorMessage);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int SyncCodeExtraInfo(IntPtr cardID, IntPtr varData, ref IntPtr cardUID, ref IntPtr transponderTypeAfterCode, 
            ref IntPtr userInput, ref int chipType, ref int chipVersion, ref IntPtr laserParametersFront, ref IntPtr laserParametersBack, ref IntPtr errorMessage);

        [DllImport("UniC10_Plugin.dll")]
        public static extern IntPtr GetDLLVersion();

        [DllImport("UniC10_Plugin.dll")]
        public static extern int IsPCSCReader(IntPtr readerName);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int GetCodingState();

        [DllImport("UniC10_Plugin.dll")]
        public static extern int CheckReaderConnection();

        [DllImport("UniC10_Plugin.dll")]
        public static extern void DisconnectReader();

        [DllImport("UniC10_Plugin.dll")]
        public static extern int GetConnectedComPort(ref byte comPort);

        [DllImport("UniC10_Plugin.dll")]
        public static extern void SetLanguage(IntPtr lang);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int PerformRegistration(IntPtr parent);

        [DllImport("UniC10_Plugin.dll")]
        public static extern IntPtr GetCustomerCode();

        [DllImport("UniC10_Plugin.dll")]
        public static extern IntPtr GetReaderSNR();

        [DllImport("UniC10_Plugin.dll")]
        public static extern void ClearRegistration();

        [DllImport("UniC10_Plugin.dll")]
        public static extern int SearchCards(IntPtr transType, ref IntPtr transDesc);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int SearchCardsExtraInfo(IntPtr transType, ref IntPtr transDesc);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int ReadLegicMaster();

        [DllImport("UniC10_Plugin.dll")]
        public static extern int CheckLegicMasters(ref IntPtr missingMasters);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int ReadLegicMasterMemory(ref IntPtr masters);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int ReadLegicAdvantStamp(byte segNum, ref IntPtr masters);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int AbortCoding();

        [DllImport("UniC10_Plugin.dll")]
        public static extern int GetLoadedCommissionTransType(ref IntPtr transType);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int FreeLog(Int32 logHandle);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int GetLog(Int32 logHandle, ref IntPtr cardUID, ref Int32 createdDate,
            ref byte codingResult, ref IntPtr shortDesc, ref IntPtr cardID, ref IntPtr varData);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int GetCombiLog(Int32 logHandle, byte combiIndex, ref IntPtr cardUID, 
            ref Int32 createdDate, ref byte codingResult, ref IntPtr shortDesc, ref IntPtr cardID, 
            ref IntPtr varData);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int LoadReadDefinition(IntPtr readDefFile);

        [DllImport("UniC10_Plugin.dll")]
        public static extern int ReadCard(ref IntPtr readData);

        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        public delegate void TCodingCallback(Int32 wParam, Int32 lParam);
        private TCodingCallback fpCodingCallback;

        #endregion

        public frmMain()
        {
            InitializeComponent();
            fpCodingCallback = new TCodingCallback(CodingCallback);
        }

        private void LogCodingResult(Int32 wParam, Int32 lParam)
        {
            switch (wParam)
            {
                case 0:
                    lbLog.Items.Add("Start");
                    pbCoding.Value = 0;
                    currentCodingSteps = 0;
                    if (lastCodingSteps == 0)
                    {
                        pbCoding.Style = ProgressBarStyle.Marquee;
                    }
                    else
                    {
                        pbCoding.Style = ProgressBarStyle.Continuous;
                        pbCoding.Maximum = lastCodingSteps;
                    }
                    break;
                case 1:
                    lbLog.Items.Add("Success");
                    pbCoding.Value = pbCoding.Maximum;
                    pbCoding.Style = ProgressBarStyle.Continuous;
                    DisplayLog(lParam);
                    FreeLog(lParam);
                    lastCodingSteps = currentCodingSteps;
                    break;
                case 2:
                    lbLog.Items.Add("Fail");
                    pbCoding.Value = pbCoding.Maximum;
                    pbCoding.Style = ProgressBarStyle.Continuous;
                    DisplayLog(lParam);
                    FreeLog(lParam);
                    lastCodingSteps = currentCodingSteps;
                    break;
                case 3:
                    lbLog.Items.Add("Removed");
                    break;
                case 4:
                    lbLog.Items.Add("Error");
                    break;
                case 5:
                    currentCodingSteps++;
                    if (pbCoding.Style != ProgressBarStyle.Marquee)
                        pbCoding.PerformStep();
                    break;
                case 7:
                    lbLog.Items.Add("Card finished");
                    break;
            }
        }

        public void CodingCallback(Int32 wParam, Int32 lParam)
        {
            LogCodingResult(wParam, lParam);
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x804D)
            {
                LogCodingResult(m.WParam.ToInt32(), m.LParam.ToInt32());
            }
            else
            {
                base.WndProc(ref m);
            }
        }

        private void DisplayLog(int logHandle)
        {
            IntPtr cardUID = IntPtr.Zero;
            int createdDate = 0;
            byte codingResult = 0;
            IntPtr shortDesc = IntPtr.Zero;
            IntPtr cardID = IntPtr.Zero;
            IntPtr varData = IntPtr.Zero;
            string sCodingResult;

            // If just one commission is loaded, calling GetLog instead of GetCombiLog leads to the same result.
            for (byte i = 0; i < numCommissions; i++) 
            {
                cardUID = IntPtr.Zero;
                shortDesc = IntPtr.Zero;
                cardID = IntPtr.Zero;
                varData = IntPtr.Zero;
                
                if (GetCombiLog(logHandle, i, ref cardUID, ref createdDate, ref codingResult, ref shortDesc,
                    ref cardID, ref varData) == 0)
                    {
                        if (codingResult > 0)
                            sCodingResult = "OK";
                        else
                            sCodingResult = "FAIL";
                        DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, 0);
                        dt = dt.AddSeconds(createdDate).ToLocalTime();
                        lbLog.Items.Add("Card " + (i+1).ToString() + ": " + Marshal.PtrToStringUni(cardUID) + ", " + dt.ToString() + 
                            ", " + sCodingResult + ", " + Marshal.PtrToStringUni(shortDesc));
                        lbLog.TopIndex = lbLog.Items.Count - 1;
                    }
                FreeWideChar(cardUID);
                FreeWideChar(shortDesc);
                FreeWideChar(cardID);
                FreeWideChar(varData);
            }
        }
        
        private void UpdateReaderConnection()
        {
            switch (CheckReaderConnection())
            {
                case 0:
                    byte comPort = 0;
                    GetConnectedComPort(ref comPort);
                    if (comPort > 0)
                    {
                        lConnectionState.Text = "Connected@COM" + comPort.ToString();
                    }
                    else
                    {
                        lConnectionState.Text = "Connected";
                    }
                    break;
                case 2: lConnectionState.Text = "Not connected, autoconnect"; break;
                default: lConnectionState.Text = "Not connected"; break;
            }
        }

        private void UpdateIsPCSCLabel()
        {
            IntPtr readerName = Marshal.StringToHGlobalUni(cbReaderNames.Text);
            int res = IsPCSCReader(readerName);
            if (res == 1)
                lIsPCSC.Text = "(PCSC)";
            else
                lIsPCSC.Text = "(RS232)";
            Marshal.FreeHGlobal(readerName);
        }

        private void frmMain_Shown(object sender, EventArgs e)
        {
            IntPtr readerNames = IntPtr.Zero;
            GetRegisteredReaderNames(ref readerNames);
            string sReaderNames = Marshal.PtrToStringUni(readerNames);
            string sName = "";
            foreach (char c in sReaderNames) {
                if (c == 0x02) {
                    cbReaderNames.Items.Add(sName);
                    sName = "";
                } else {
                    sName += c;
                }
            }
            FreeWideChar(readerNames);
            cbReaderNames.Items.Add("AUTOCONNECT");
            foreach (char c in sReaderNames)
            {
                if (c == 0x02)
                {
                    cbReaderNames.Items.Add("AUTOCONNECT:"+sName);
                    sName = "";
                }
                else
                {
                    sName += c;
                }
            }
            cbReaderNames.SelectedIndex = 4;

            IntPtr dllVersion = GetDLLVersion();
            lDLLVersion.Text = Marshal.PtrToStringUni(dllVersion);
            FreeWideChar(dllVersion);

            UpdateIsPCSCLabel();

            tUpdateCodingState.Enabled = true;
        }

        private void bPrepareCoding_Click(object sender, EventArgs e)
        {
            lastCodingSteps = 0;
            pbCoding.Value = 0;
            IntPtr commXML = Marshal.StringToHGlobalUni(edXMLFileName.Text.Replace("/", "\u0002"));
            IntPtr parent;
            if (chbNoGUI.Checked)
                parent = IntPtr.Zero;
            else
                parent = Handle;
            int ecs = 0;
            byte hasCardID = 0;
            IntPtr maxCardID = IntPtr.Zero;
            IntPtr varData = IntPtr.Zero;
            IntPtr codingCallback;
            if (chbCallbackMode.Checked)
                codingCallback = IntPtr.Zero;
            else
                codingCallback = Handle;
            int res = PrepareCoding(commXML, codingCallback, parent, ref ecs, ref hasCardID, ref maxCardID, ref varData);
            if (res == 0)
            {
                if (hasCardID == 1)
                {
                    edCardID.Enabled = true;
                    lCardID.Enabled = true;
                    lMaxCardID.Enabled = true;
                    lMaxCardID.Text = "(MAX: " + Marshal.PtrToStringUni(maxCardID) + ")";
                }
                else
                {
                    edCardID.Enabled = false;
                    lCardID.Enabled = false;
                    lMaxCardID.Enabled = false;
                }
                string sVarItems = Marshal.PtrToStringUni(varData);
                string sVarItem = "";
                string s = "";
                int col = 0;
                
                lvVarData.Items.Clear();
                foreach (char ci in sVarItems)
                {
                    if (ci == 0x02)
                    {
                        col = 0;
                        s = "";
                        for (int j = 0; j < sVarItem.Length; j++) 
                        {
                            if ((sVarItem[j] == 0x03) || (j == sVarItem.Length - 1))
                            {
                                if (j == sVarItem.Length - 1)
                                    s += sVarItem[j];
                                if (col == 0)
                                {
                                    ListViewItem lvi = new ListViewItem(s);
                                    lvi.SubItems.Add("");
                                    lvi.SubItems.Add("");
                                    lvi.SubItems.Add("");
                                    lvVarData.Items.Add(lvi);
                                }
                                else
                                {
                                    lvVarData.Items[lvVarData.Items.Count - 1].SubItems[col].Text = s;
                                }
                                col++;
                                s = "";
                            }
                            else
                            {
                                s += sVarItem[j];
                            }
                        }
                        sVarItem = "";
                    }
                    else
                    {
                        sVarItem += ci;
                    }
                }
                lvVarData.Columns[0].Width = -2;
                lvVarData.Columns[1].Width = -2;
                lvVarData.Columns[2].Width = -1;
                lvVarData.Columns[3].Width = -2;
            }
            else
            {
                switch (res)
                {
                    case 1: MessageBox.Show("File not found."); break;
                    case 2: MessageBox.Show("No reader connected."); break;
                    case 3: MessageBox.Show("Reader cannot code commission."); break;
                    case 4: MessageBox.Show("License invalid."); break;
                    case 5: MessageBox.Show("CRC validation failed."); break;
                    case 6: MessageBox.Show("File deprecated."); break;
                    case 7: MessageBox.Show("Transponder type unknown."); break;
                    case 8: MessageBox.Show("Commission file invalid."); break;
                    case 9: MessageBox.Show("Commission has external data source fields."); break;
                    case 10: MessageBox.Show("Combi commission with duplicate transponder type."); break;
                    case 11: MessageBox.Show("Could not autoconnect reader."); break;
                    default: MessageBox.Show("Not OK."); break;
                }
            }
            Marshal.FreeHGlobal(commXML);
            FreeWideChar(maxCardID);
            FreeWideChar(varData);

            if (res == 0)
            {
                // Determine how many commissions were loaded in PrepareCoding
                IntPtr transType = IntPtr.Zero;
                res = GetLoadedCommissionTransType(ref transType);
                if (res == 0)
                {
                    string sTransType = Marshal.PtrToStringUni(transType);
                    numCommissions = 1;
                    foreach (char ci in sTransType)
                    {
                        if (ci == 0x02)
                        {
                            numCommissions++;
                        }
                    }
                    FreeWideChar(transType);
                }
            }
        }

        private void bCode_Click(object sender, EventArgs e)
        {
            string sVarData = "";
            for (int i = 0; i < lvVarData.Items.Count; i++)
                sVarData += lvVarData.Items[i].Text + "\u0003" + lvVarData.Items[i].SubItems[3].Text + "\u0002";
            IntPtr cardID = Marshal.StringToHGlobalUni(edCardID.Text);
            IntPtr varData = Marshal.StringToHGlobalUni(sVarData);
            int res;

            if (chbSyncCode.Checked)
            {
                IntPtr cardUID = IntPtr.Zero;
                IntPtr errorMessage = IntPtr.Zero;
                IntPtr transponderTypeAfterCode = IntPtr.Zero;
                IntPtr userInput = IntPtr.Zero;
                int chipType = -1;
                int chipVersion = -1;
                IntPtr laserParametersFront = IntPtr.Zero;
                IntPtr laserParametersBack = IntPtr.Zero;
                res = SyncCodeExtraInfo(cardID, varData, ref cardUID, ref transponderTypeAfterCode, ref userInput, ref chipType, ref chipVersion,
                    ref laserParametersFront, ref laserParametersBack, ref errorMessage);

                switch (res)
                {
                    case 0: MessageBox.Show("Coding successful.\n" +
                        "Card UID = " + Marshal.PtrToStringUni(cardUID) + "\n" +
                        "Transponder after code = " + Marshal.PtrToStringUni(transponderTypeAfterCode) + "\n" +
                        "UserInput = " + Marshal.PtrToStringUni(userInput) + "\n" +
                        "Chip Type = " + chipType + "\n" +
                        "Chip Version = " + chipVersion + "\n" +
                        "Laser Params = " + Marshal.PtrToStringUni(laserParametersFront) + " / " + Marshal.PtrToStringUni(laserParametersBack) + "\n");
                        break;
                    case 1: MessageBox.Show("Invalid card ID."); break;
                    case 2: MessageBox.Show("Invalid var data string."); break;
                    case 3: MessageBox.Show("Invalid coding state. Must be 'online'."); break;
                    case 4: MessageBox.Show("Invalid license."); break;
                    case 5: MessageBox.Show("Combi coding not supported."); break;
                    case 6: MessageBox.Show("No card in field."); break;
                    case 7: MessageBox.Show("Coding error: " + Marshal.PtrToStringUni(errorMessage)); break;
                    case 8: MessageBox.Show("Unable to parse laser parameters."); break;
                }
                FreeWideChar(cardUID);
                FreeWideChar(errorMessage);
                FreeWideChar(transponderTypeAfterCode);
                FreeWideChar(userInput);
                FreeWideChar(laserParametersFront);
                FreeWideChar(laserParametersBack);
            }
            else
            {
                if (edSearchSleep.Text == "")
                    res = Code(cardID, varData);
                else
                    res = SleepAndCode(cardID, varData, Convert.ToInt32(edSearchSleep.Text));
                switch (res)
                {
                    case 1: MessageBox.Show("Invalid card ID."); break;
                    case 2: MessageBox.Show("Invalid var data string."); break;
                    case 3: MessageBox.Show("Invalid coding state. Must be 'online'."); break;
                    case 4: MessageBox.Show("Invalid license."); break;
                    case 5: MessageBox.Show("Invalid coding mode. Callback mode has to be off."); break;
                }
            }
            Marshal.FreeHGlobal(cardID);
            Marshal.FreeHGlobal(varData);
        }

      
        private void bCodeSync_Click(object sender, EventArgs e)
        {
            string sVarData = "";
            for (int i = 0; i < lvVarData.Items.Count; i++)
                sVarData += lvVarData.Items[i].Text + "\u0003" + lvVarData.Items[i].SubItems[3].Text + "\u0002";
            IntPtr cardID = Marshal.StringToHGlobalUni(edCardID.Text);
            IntPtr varData = Marshal.StringToHGlobalUni(sVarData);
            int res = CodeWithCallback(cardID, varData, Convert.ToInt32(edSearchSleep.Text), fpCodingCallback);
            switch (res)
            {
                case 1: MessageBox.Show("Invalid card ID."); break;
                case 2: MessageBox.Show("Invalid var data string."); break;
                case 3: MessageBox.Show("Invalid coding state. Must be 'online'."); break;
                case 4: MessageBox.Show("Invalid license."); break;
                case 5: MessageBox.Show("Invalid coding mode. Callback mode has to be on."); break;
            }
            Marshal.FreeHGlobal(cardID);
            Marshal.FreeHGlobal(varData);
        }

        private void bConnect_Click(object sender, EventArgs e)
        {
            try
            {
                byte comPort = Convert.ToByte(edComPort.Text);
                IntPtr readerName;
                if (edIP.Text != "")
                    readerName = Marshal.StringToHGlobalUni(cbReaderNames.Text + "@" + edIP.Text);
                else
                    readerName = Marshal.StringToHGlobalUni(cbReaderNames.Text);
                int res = ConnectReader(readerName, comPort, 0, 0xFF, 0xFF, 0xFF);
                Marshal.FreeHGlobal(readerName);
                switch (res)
                {
                    case 0: UpdateReaderConnection(); break;
                    case 1: MessageBox.Show("Invalid reader name"); break;
                    case 2: MessageBox.Show("Unable to connect"); break;
                }
            }
            catch
            {
                MessageBox.Show("Invalid COM Port");
            }
        }

        private void cbReaderNames_SelectedIndexChanged(object sender, EventArgs e)
        {
            UpdateIsPCSCLabel();
        }

        private void tUpdateCodingState_Tick(object sender, EventArgs e)
        {
            switch (GetCodingState())
            {
                case 0: lCodingState.Text = "Coding State: Offline"; break;
                case 1: lCodingState.Text = "Coding State: Online"; break;
                case 2: lCodingState.Text = "Coding State: Scan for Card"; break;
                case 3: lCodingState.Text = "Coding State: Create Card"; break;
                case 4: lCodingState.Text = "Coding State: Wait for remove"; break;
            }
        }

        private void bCheckConnection_Click(object sender, EventArgs e)
        {
            UpdateReaderConnection();
        }

        private void bDisconnectReader_Click(object sender, EventArgs e)
        {
            DisconnectReader();
            UpdateReaderConnection();
        }

        private void bSetLanguage_Click(object sender, EventArgs e)
        {
            IntPtr language = Marshal.StringToHGlobalUni(edLanguage.Text);
            SetLanguage(language);
            Marshal.FreeHGlobal(language);
        }

        private void bCheckRegistration_Click(object sender, EventArgs e)
        {
            switch (PerformRegistration(Handle))
            {
                case 0: MessageBox.Show("Perform Registration OK"); break;
                case 1: MessageBox.Show("Registration invalid."); break;
                case 2: MessageBox.Show("Already registered."); break;
            }
        }

        private void bGetCustomerCode_Click(object sender, EventArgs e)
        {
            IntPtr customerCode = GetCustomerCode();
            MessageBox.Show(Marshal.PtrToStringUni(customerCode));
            FreeWideChar(customerCode);
        }

        private void bClearRegistration_Click(object sender, EventArgs e)
        {
            ClearRegistration();
        }

        private void bSearchCards_Click(object sender, EventArgs e)
        {
            IntPtr transType = Marshal.StringToHGlobalUni(cbTransType.Text);
            IntPtr transDesc = IntPtr.Zero;
            int res;
            if (cbExtraInfo.Checked)
                res = SearchCardsExtraInfo(transType, ref transDesc);
            else 
                res = SearchCards(transType, ref transDesc);
            switch (res)
            {
                case 0: MessageBox.Show("Cards: " + Marshal.PtrToStringUni(transDesc)); break;
                case 1: MessageBox.Show("No reader connected."); break;
                case 2: MessageBox.Show("Invalid coding state."); break;
                case 3: MessageBox.Show("Unknown transponder type."); break;
                case 4: MessageBox.Show("Error reading chip type and version."); break;
            }
            FreeWideChar(transDesc);
            Marshal.FreeHGlobal(transType);
        }

        private void bReadLegicMaster_Click(object sender, EventArgs e)
        {
            switch (ReadLegicMaster())
            {
                case 0: MessageBox.Show("Master data added successfully."); break;
                case 1: MessageBox.Show("Connected reader does not support Legic media."); break;
                case 2: MessageBox.Show("No card in range."); break;
                case 3: MessageBox.Show("Invalid coding state."); break;
                case 4: MessageBox.Show("Could not add master data."); break;
            }

        }

        private void bCheckLegicMasters_Click(object sender, EventArgs e)
        {
            IntPtr missingMasters = IntPtr.Zero;
            switch (CheckLegicMasters(ref missingMasters))
            {
                case 0: MessageBox.Show("Missing masters: " + Marshal.PtrToStringUni(missingMasters)); break;
                case 1: MessageBox.Show("Connected reader does not support Legic media."); break;
                case 2: MessageBox.Show("Loaded commission is no Legic commission."); break;
                case 3: MessageBox.Show("Invalid coding state."); break;
                case 4: MessageBox.Show("Could not read master data."); break;
            }
            FreeWideChar(missingMasters);
        }

        private void bSetVarValue_Click(object sender, EventArgs e)
        {
            if (lvVarData.SelectedItems.Count != 0)
                lvVarData.SelectedItems[0].SubItems[3].Text = edVarValue.Text;
            else
                MessageBox.Show("No item selected.");
        }

        private void bAbortCoding_Click(object sender, EventArgs e)
        {
            if (AbortCoding() > 0)
                MessageBox.Show("Invalid coding state. Must be 'scan for card' or 'wait for remove'.");
        }

        private void bGetLoadedCommissionTransType_Click(object sender, EventArgs e)
        {
            IntPtr transType = IntPtr.Zero;
            switch (GetLoadedCommissionTransType(ref transType))
            {
                case 0: MessageBox.Show("Transponder type:\n" + Marshal.PtrToStringUni(transType).Replace("\u0002", "\n")); break;
                case 1: MessageBox.Show("No commission loaded."); break;
            }
            FreeWideChar(transType);
        }

        private void bSelectFileName_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = 
                "UniC10 Plugin Coding Mask (*.xml)|*.xml|"+
                "UniC10 Plugin Combicoding Definition File (*.cdf)|*.cdf";
            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                edXMLFileName.Text = dlg.FileName;
        }

        private void bExit_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void bAddFileName_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "UniC10 Plugin Coding Mask (*.xml)|*.xml";
            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                edXMLFileName.Text = edXMLFileName.Text + "/" + dlg.FileName;
        }

        private void bSelectReadDefinitionFileName_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter =
                "UniC10 Plugin Read Definition File (*.rdx)|*.rdx";
            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                edReadDefinitionFileName.Text = dlg.FileName;
        }

        private void bLoadReadDefinition_Click(object sender, EventArgs e)
        {
            IntPtr readDefFile = Marshal.StringToHGlobalUni(edReadDefinitionFileName.Text);
            int res = LoadReadDefinition(readDefFile);
            switch (res)
            {
                case 0: MessageBox.Show("OK"); break;
                case 1: MessageBox.Show("File not found."); break;
                case 2: MessageBox.Show("File is no valid read definition file."); break;
            }
            Marshal.FreeHGlobal(readDefFile);
        }


        private void bReadCard_Click(object sender, EventArgs e)
        {
            IntPtr readData = IntPtr.Zero;
            int res = ReadCard(ref readData);
            switch (res)
            {
                case 0: MessageBox.Show("Card ID number: " + Marshal.PtrToStringUni(readData)); break;
                case 1: MessageBox.Show("Invalid coding state. Must be online or offline"); break;
                case 2: MessageBox.Show("No read definition file loaded."); break;
                case 3: MessageBox.Show("No reader connected."); break;
                case 4: MessageBox.Show("Connected reader cannot read specified transponder."); break;
                case 5: MessageBox.Show("Zero or more than one transponder of specified type found."); break;
                case 6: MessageBox.Show("Data could not be read."); break;
            }
            FreeWideChar(readData);
        }

        private void bGetReaderSNR_Click(object sender, EventArgs e)
        {
            IntPtr readerSNR = GetReaderSNR();
            MessageBox.Show("Reader SNR: " + Marshal.PtrToStringUni(readerSNR));
            FreeWideChar(readerSNR);
        }

        private void bAnalyzeCodingMask_Click(object sender, EventArgs e)
        {
            IntPtr commXML = Marshal.StringToHGlobalUni(edXMLFileName.Text.Replace("/", "\u0002"));
            byte hasCardID = 0;
            IntPtr maxCardID = IntPtr.Zero;
            IntPtr varData = IntPtr.Zero;
            IntPtr transType = IntPtr.Zero;

            int res = AnalyzeCodingMask(commXML, ref transType, ref hasCardID, ref maxCardID, ref varData);
            Marshal.FreeHGlobal(commXML);

            if (res == 0)
            {
                commXML = Marshal.StringToHGlobalUni(System.IO.File.ReadAllText(edXMLFileName.Text, Encoding.Default));
                IntPtr frontLayout = IntPtr.Zero;
                IntPtr frontParameters = IntPtr.Zero;
                IntPtr backLayout = IntPtr.Zero;
                IntPtr backParameters = IntPtr.Zero;
                res = GetLaserParameters(commXML, ref frontLayout, ref frontParameters, ref backLayout, ref backParameters);
                if (res == 0)
                {
                    MessageBox.Show(
                        "TransType: " + Marshal.PtrToStringUni(transType) + 
                        "\nHasCardID: " + hasCardID.ToString() + 
                        "\nMaxCardID: " + Marshal.PtrToStringUni(maxCardID) + 
                        "\nVarData: " + Marshal.PtrToStringUni(varData) +
                        "\nFront Layout: " + Marshal.PtrToStringUni(frontLayout) +
                        "\nFront Parameters: " + Marshal.PtrToStringUni(frontParameters) +
                        "\nBack Layout: " + Marshal.PtrToStringUni(backLayout) +
                        "\nBack Parameters: " + Marshal.PtrToStringUni(backParameters));
                }
                else
                {
                    MessageBox.Show("Error in GetLaserParameters.");
                }
                Marshal.FreeHGlobal(commXML);
                FreeWideChar(frontLayout);
                FreeWideChar(frontParameters);
                FreeWideChar(backLayout);
                FreeWideChar(backParameters);
            }
            else
            {
                MessageBox.Show("Error in AnalyzeCodingMask.");
            }
            
            FreeWideChar(maxCardID);
            FreeWideChar(varData);
            FreeWideChar(transType);            
        }

        private void bReadLegicMasterMemory_Click(object sender, EventArgs e)
        {
            IntPtr masters = IntPtr.Zero;
            switch (ReadLegicMasterMemory(ref masters))
            {
                case 0: MessageBox.Show("Masters: " + Marshal.PtrToStringUni(masters)); break;
                case 1: MessageBox.Show("No Legic reader connected."); break;
                case 2: MessageBox.Show("Could not read master data."); break;
            }
            FreeWideChar(masters);
        }

        private void bReadLegicAdvantStamp_Click(object sender, EventArgs e)
        {
            byte segNum = Convert.ToByte(edSegNum.Text);
            IntPtr stamp = IntPtr.Zero;
            switch (ReadLegicAdvantStamp(segNum, ref stamp))
            {
                case 0: MessageBox.Show("Stamp: " + Marshal.PtrToStringUni(stamp)); break;
                case 1: MessageBox.Show("No Legic reader connected."); break;
                case 2: MessageBox.Show("Invalid coding state."); break;
                case 3: MessageBox.Show("No card found."); break;
                case 4: MessageBox.Show("Segment number not found."); break;
            }
            FreeWideChar(stamp);
        }
    }
}
